package com.macaline.util;

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import net.sf.json.JSONObject;

/**
 * 地理位置相关工具类
 * @author warm_joy
 */
@SuppressWarnings("unused")
public class AddressUtil {
	
	static {
		addressMap = new HashMap<String, String>();
	}
	
	//对无处存放地理位置的用户进行持久化保存
	public static Map<String, String> addressMap;
	
	private String Ip;//需要查询的ip地址
	private String latitude;//维度
	private String longitude;//经度
	
	//用于获取地址信息的json数据
	private JSONObject addressJson = null;
	//所有返回结果的json类型
	private JSONObject resultJson = null;
	//返回管理经纬信息的json对象
	private JSONObject pointJson = null;
	
	/**
	 * 经纬度计算距离的转换单位
	 */
	private static double EARTH_RADIUS = 6378.137;
	
	/**
	 * 对游客的地理位置对性持久化保存
	 * 当长度大于一万时进行清空
	 * @author warm_joy
	 * @return
	 */
	public static Map<String, String> getAddressMap() {
		if(addressMap.size() > 10000) {
			addressMap.clear();
		}
		return addressMap;
	}
	
	/**
	 * 
	 * Description:  <br/>
	 *	</p>
	 * @param latitude 
	 * @param longitude 
	 */
	/**
	 * 通过百度接口获取地理位置信息
	 * 返回结果格式请参考接口：http://api.map.baidu.com/geocoder
	 * @author warm_joy
	 * @param latitude 维度信息
	 * @param longitude 经度信息
	 */
	public AddressUtil(String latitude, String longitude) {
		super();
		this.latitude = latitude;
		this.longitude = longitude;
		initAddressByPoint(latitude,longitude);
	}
	
	/**
	 * 通过百度接口获取地理位置信息
	 * 返回结果格式请参考接口：http://api.map.baidu.com/geocoder
	 * @author warm_joy
	 * @param ip 需要查询的ip地址
	 */
	public AddressUtil(String ip) {
		this.Ip = ip;
		initAddressByIP(ip);
	}

	/**
	 * 通过ip查询地理信息，在new对象是时已经运行此方法
	 * @author warm_joy
	 * @param ip 需要被查询的ip地址
	 */
	public void initAddressByIP(String ip){
		try {
			//通过ip查询地理信息的ip地址
			String urlString = "http://api.map.baidu.com/location/ip?ak=kYermFA2vFEkaf6CPgFoAv2ml5cFe0t2&ip=" + ip + "&coor=bd09ll";
			//新创建url对象
			URL url = new URL(urlString);
			URLConnection con = url.openConnection();
	        //设置请求需要返回的数据类型和字符集类型
	        con.setRequestProperty("Content-Type", "application/json;charset=UTF-8");  
	        //允许写出
	        con.setDoOutput(true);
	        //允许读入
	        con.setDoInput(true);
	        //不使用缓存
	        con.setUseCaches(false);
	        //得到响应码
	        InputStream input = con.getInputStream();
	        DataInputStream is = new DataInputStream(input);
	        //将响应流转换成字符串
	        byte[] b = new byte[1024];
	        int length;
	        StringBuffer sb = new StringBuffer() ;
	        while((length = is.read(b)) > 0) {
	        	sb.append(new String(b,0,length));
	        }
	        //关闭掉使用完毕的流
	        input.close();
	        is.close();
	        String addressString = unicodeToString(sb.toString());
	        //保存所有的返回信息
	        pointJson = JSONObject.fromObject(addressString).getJSONObject("content").getJSONObject("point");
	       //通过ip差查询出的经纬度信息更新更全面的地址信息
	        String lat = getLatitude();
	        String lon = getLongitude();
	        //通过此方法获取的经纬度信息更新类型信息
	        initAddressByPoint(lat, lon);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	

	/**
	 * 通过经纬度获取地理位置信息
	 * @author warm_joy
	 * @param latitude 维度信息
	 * @param longitude 经度信息
	 */
	public void initAddressByPoint(String latitude,String longitude) {
		HttpClient client = HttpClients.createDefault();// 创建默认http连接
        HttpPost post = new HttpPost("http://api.map.baidu.com/geocoder/v2/");// 创建一个post请求
        List<NameValuePair> paramList = new ArrayList<NameValuePair>();
        paramList.add(new BasicNameValuePair("ak", "OxunDd3soQrlGrjPYRG63FGDqpGAFG4n"));//传递的参数
        paramList.add(new BasicNameValuePair("sn", "CH"));//传递的参数
        paramList.add(new BasicNameValuePair("location", latitude + "," + longitude));//传递的参数

        // 把参转码后放入请求实体中
        HttpEntity entitya;
        //保存返回信息的String
        String xmlString = null;
		try {
			//对传入的参数进行编码编辑
			entitya = new UrlEncodedFormEntity(paramList, "utf-8");
			post.setEntity(entitya);// 把请求实体放post请求中
	        HttpResponse response = client.execute(post);// 用http连接去执行get请求并且获得http响应
	        HttpEntity entity = response.getEntity();// 从response中取到响实体
	        xmlString = EntityUtils.toString(entity);// 把响应实体转成文本
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			
		}
		
		//如果返回结果为null 失败
		if(xmlString == null) {
		}else {
			JSONObject stringToJson = XmlUtil.stringToJson(xmlString);
			//得到并保存返回的所有数据新的jsonObject信息
			resultJson = stringToJson;
			//获得并保存关于地址信息的JSONObject
			addressJson = resultJson.getJSONObject("result").getJSONObject("addressComponent");
		}
	}
	
	/**
	 * 获取国家位置信息
	 * @author warm_joy
	 * @return 返回所处国家信息 列如：中国
	 */
	public String getCountry() {
		return addressJson.getString("country");
	}
	/**
	 * 
	* <p>@author warm_joy </p>
	* <p>Description:  </p>
	* <p>Date: 2019-04-28 17:22</p>
	* @return
	 */
	/**
	 * 获取所处省份信息
	 * @author warm_joy
	 * @return 省份信息 例如：山东省
	 */
	public String getProvince() {
		return addressJson.getString("province");
	}
	
	
	/**
	 * 获取城市信息
	 * @author warm_joy
	 * @return 返回所处城市信息 列如：潍坊市
	 */
	public String getCity() {
		return addressJson.getString("city");
	}
	/**
	 * 
	* <p>@author warm_joy </p>
	* <p>Description: </p>
	* <p>Date: 2019-04-28 17:22</p>
	* @return
	 */
	/**
	 * 获取区域信息
	 * @author warm_joy
	 * @return 返回所处区域信息 例如：奎文区
	 */
	public String getDistrict() {
		return addressJson.getString("district");
	}
	/**
	 * 获取所处位置的的维度信息
	 * @author warm_joy
	 * @return 
	 */
	public String getLatitude() {
		return pointJson.getString("y");
	}
	
	/**
	 * 获取所处位置的的经度信息
	 * @author warm_joy
	 * @return 经度位置
	 */
	public String getLongitude() {
		return pointJson.getString("x");
	}
	
	/**
	 * 获取所处街道信息 
	 * @author warm_joy
	 * @return 返回所处街道信息 列如：北海路
	 */
	public String getStreet() {
		return addressJson.getString("street");
	}
	
	/**
	 * 返回服务器返回的全部信息的JSONObject的对象
	 * @author warm_joy
	 * @return
	 */
	public JSONObject getResultJsonObject() {
		return resultJson;
	}
	
	/**
	 * 返回服务器返回的关于地址信息的JSONObject对象
	 * @author warm_joy
	 * @return
	 */
	public JSONObject getAddressJsonObject() {
		return addressJson;
	}
	
	/**
	 * 返回服务器返回的关于地址信息的JSONObject对象
	 * @author warm_joy
	 * @return
	 */
	public JSONObject getJPointsonObject() {
		return pointJson;
	}
	
	/**
	 * 
	* <p>@author warm_joy </p>
	* <p>Description: </p>
	* <p>Date: 2019-04-12 11:51</p>
	* @param str 
	* @return
	 */
	/**
	 * unicode码转换中文字符串
	 * @author warm_joy
	 * @param str 需要转换的String 字符串
	 * @return 装换好的字符串
	 */
	public String unicodeToString(String str) {
		 
		Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
		Matcher matcher = pattern.matcher(str);
		char ch;
		while (matcher.find()) {
			//group 6728
			String group = matcher.group(2);
			//ch:'木' 26408
			ch = (char) Integer.parseInt(group, 16);
			//group1 \u6728
			String group1 = matcher.group(1);
			str = str.replace(group1, ch + "");
		}
		return str;
	}
	
	/**
	 * 通过经纬度获取相隔距
	 * @author warm_joy
	 * @param lat1 第一个位置的维度
	 * @param lng1 第一个位置的经度
	 * @param lat2 第二个地址的维度
	 * @param lng2 第二个地址的经度
	 * @return
	 */
	public static double getDistance(double lat1, double lng1, double lat2,
			double lng2) {
		double radLat1 = rad(lat1);
		double radLat2 = rad(lat2);
		double a = radLat1 - radLat2;
		double b = rad(lng1) - rad(lng2);
		double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
				+ Math.cos(radLat1) * Math.cos(radLat2)
				* Math.pow(Math.sin(b / 2), 2)));
		s = s * EARTH_RADIUS;
		s = Math.round(s * 10000d) / 10000d;
		s = s * 1000;
		return s;
	}
	private static double rad(double d) {
		return d * Math.PI / 180.0;
	}
	
	/**
	 * 得到当前的ip
	 * @author warm_joy
	 * @return 进行地址分析的ip地址
	 */
	public String getip() {
		return Ip;
	}
	
	/**
	 * 测试方法
	 * @author warm_joy
	 * @param args
	 */
	public static void main(String[] args) {
		AddressUtil addressByPointUtil = new AddressUtil("27.205.150.231");
		System.out.println(addressByPointUtil.getAddressJsonObject());
	}
}
